package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.maiji.cloud.config.MyRedisConfig;
import com.maiji.cloud.entities.login.AppUser;
import com.maiji.cloud.entities.shopingmall.Goods;
import com.maiji.cloud.entities.shopingmall.ShopingCart;
import com.maiji.cloud.mapper.ShopingCartMapper;
import com.maiji.cloud.microservice.UserInfoService;
import com.maiji.cloud.request.shopingmall.ShopingCartCheckReqData;
import com.maiji.cloud.response.*;
import com.maiji.cloud.response.shopingmall.GoodsResData;
import com.maiji.cloud.response.shopingmall.ShopingCartChosenResData;
import com.maiji.cloud.response.shopingmall.ShopingCartResData;
import com.maiji.cloud.response.shopingmall.ShopingOrderResData;
import com.maiji.cloud.service.GoodsService;
import com.maiji.cloud.service.ShopingCartService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.utils.Arith;
import com.maiji.cloud.utils.BaseService;
import com.maiji.cloud.utils.RedisUtil;
import com.maiji.cloud.utils.UUID_MD5;
import org.eclipse.jetty.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class ShopingCartServiceImpl extends ServiceImpl<ShopingCartMapper, ShopingCart> implements ShopingCartService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private GoodsService goodsService;

    @Override
    public BaseResDto addToShopingCart(List<String> goodsIds, Integer quantity, String token) {
        BaseResDto baseResDto = new BaseResDto(Status.SUCCESS);
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        String userId = appUser.getUuId();
        for (String goodsId: goodsIds) {
            Goods goods = goodsService.selectById(goodsId);
            Double originalPayable = Arith.multiplys(2, goods.getOriginalPrice(), quantity);
            Double presentPayable = Arith.multiplys(2, goods.getPresentPrice(), quantity);
            Integer weightTotal = goods.getWeight() * quantity;
            EntityWrapper<ShopingCart> entityWrapper = new EntityWrapper<>();
            entityWrapper.eq("goods_id", goodsId);
            entityWrapper.eq("user_id", userId);
            entityWrapper.eq("add_auto", false);
            entityWrapper.eq("status", 0);
            ShopingCart shopingCart  = selectOne(entityWrapper);
            if (shopingCart == null) {
                shopingCart = new ShopingCart();
                shopingCart.setUuId(UUID_MD5.getUUID())
                        .setUserId(userId)
                        .setGoodsId(goodsId)
                        .setPurchaseQuantity(quantity)
                        .setOriginalPayable(originalPayable)
                        .setPresentPayable(presentPayable)
                        .setWeightTotal(weightTotal)
                        .setAddDate(new Date())
                        .setUpdateDate(new Date())
                        .setChosen(false)
                        .setAddAuto(false);
                if (! insert(shopingCart)) baseResDto.setStatus(Status.ERROR);
            } else {
                shopingCart.setPurchaseQuantity(shopingCart.getPurchaseQuantity() + quantity)
                        .setOriginalPayable(shopingCart.getOriginalPayable() + originalPayable)
                        .setPresentPayable(shopingCart.getPresentPayable() + presentPayable)
                        .setWeightTotal(shopingCart.getWeightTotal() + weightTotal)
                        .setUpdateDate(new Date());
                if (! updateById(shopingCart)) baseResDto.setStatus(Status.ERROR);
            }
        }
        return baseResDto;
    }

    @Override
    public BaseMetaResDto<List<ShopingCartResData>> FindAllShopingCart(String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        String userId = appUser.getUuId();
        EntityWrapper<ShopingCart> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", userId);
        entityWrapper.eq("status", 0);
        entityWrapper.eq("add_auto", false);
        List<ShopingCart>shopingCartList = selectList(entityWrapper);
        if (shopingCartList.size() == 0) return new BaseMetaResDto<>(Status.SUCCESS);
        List<String> goodsIds = shopingCartList.parallelStream().map(ShopingCart::getGoodsId).collect(Collectors.toList());
        EntityWrapper<Goods> goodsWrapper = new EntityWrapper<>();
        goodsWrapper.in("uu_id", goodsIds);
        goodsWrapper.eq("up_down", 2);
        goodsWrapper.eq("stock_volume", 0);
        List<String> downGoodsIds = goodsService.selectList(goodsWrapper).parallelStream().map(Goods::getUuId).collect(Collectors.toList());
        if (downGoodsIds.size() > 0) {
            shopingCartList = shopingCartList.parallelStream().filter(shopingCart -> ! downGoodsIds.contains(shopingCart.getGoodsId())).collect(Collectors.toList());
            delete(entityWrapper.in("goods_id", goodsIds));
        }
        List<ShopingCartResData> data = findAllResData(shopingCartList);
        return new BaseMetaResDto<List<ShopingCartResData>>(Status.SUCCESS).setData(data);
    }

    @Override
    public BaseDataResDto<Integer> findUserShopingCartCount(String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        String userId = appUser.getUuId();
        EntityWrapper<ShopingCart> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", userId);
        entityWrapper.eq("status", 0);
        entityWrapper.eq("add_auto", false);
        Integer selectCount = selectCount(entityWrapper);
        return new BaseDataResDto<Integer>(Status.SUCCESS).setData(selectCount);
    }

    @Override
    public List<ShopingCartResData> findAllResData(List<ShopingCart> shopingCartList) {
        Set<String> goodsIds = shopingCartList.stream().map(ShopingCart::getGoodsId).collect(Collectors.toSet());
        List<GoodsResData> goodsResDataList = goodsService.findAllGoodsResData(goodsService.selectBatchIds(goodsIds), null);
        List<ShopingCartResData> shopingCartResDataList = BaseService.dealWithOneToOne(shopingCartList, "getGoodsId",
                ShopingCartResData.class, "setGoods", goodsResDataList, "getUuId", GoodsResData.class);
        return shopingCartResDataList;
    }

    @Override
    public BaseDataResDto<ShopingCartChosenResData> chosenShopingCart(ShopingCartCheckReqData data, String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        String userId = appUser.getUuId();
        EntityWrapper<ShopingCart> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", userId);
        entityWrapper.eq("status", 0);
        if (data != null) {
            String shopingCartId = data.getUuId();
            Boolean chosen = data.getChosen();
            Boolean allChosen = data.getAllChosen();
            if (StringUtil.isNotBlank(shopingCartId) && chosen != null &&
                    ! updateById(new ShopingCart().setUuId(shopingCartId).setChosen(chosen)))
                return new BaseDataResDto<>(Status.ERROR);
            entityWrapper.eq("add_auto", false);
            if (allChosen != null && ! update(new ShopingCart().setChosen(allChosen), entityWrapper))
                return new BaseDataResDto<>(Status.ERROR);
        }
        entityWrapper.eq("chosen", true);
        Double totalPresentPayable = selectList(entityWrapper).stream()
                .map(shopingCart -> shopingCart.getPresentPayable())
                .reduce(0.00, (s1, s2) -> Arith.add(2, s1, s2));
        ShopingCartChosenResData shopingCartChosenResData = new ShopingCartChosenResData().setPayableAmount(totalPresentPayable);
        return new BaseDataResDto<ShopingCartChosenResData>(Status.SUCCESS).setData(shopingCartChosenResData);
    }

    @Override
    public BaseResDto updateShopingCartQuantity(String shopingCartId, Integer purchaseQuantity) {
        ShopingCart shopingCart = selectById(shopingCartId);
        if (shopingCart == null) return new BaseResDto(Status.ERROR);
        Goods goods = goodsService.selectById(shopingCart.getGoodsId());
        if (goods == null) return new BaseResDto(Status.ERROR);
        shopingCart.setPurchaseQuantity(purchaseQuantity)
                .setOriginalPayable(Arith.multiplys(2, goods.getOriginalPrice(), purchaseQuantity))
                .setPresentPayable(Arith.multiplys(2, goods.getPresentPrice(), purchaseQuantity))
                .setWeightTotal(goods.getWeight() * purchaseQuantity)
                .setUpdateDate(new Date());
        if (! updateById(shopingCart)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto delShopingCart(List<String> shopingCartIds) {
        if (deleteBatchIds(shopingCartIds)) return new BaseResDto(Status.SUCCESS);
        return new BaseResDto(Status.ERROR);
    }

    @Override
    public Integer orderSubmitCalculate(ShopingOrderResData shopingOrderResData, List<String> shopingCartIds) {
        List<ShopingCart> shopingCartList = selectBatchIds(shopingCartIds);
        List<String> goodsIds = shopingCartList.parallelStream().map(ShopingCart::getGoodsId).collect(Collectors.toList());
        List<Goods> goodsList = goodsService.selectBatchIds(goodsIds);
        Map<String, Goods> goodsMap = goodsList.parallelStream().collect(Collectors.toMap(Goods::getUuId, goods -> goods));
        if (shopingCartList.parallelStream().anyMatch(sc -> goodsMap.get(sc.getGoodsId()).getUpDown() == 2
                && sc.getPurchaseQuantity() > goodsMap.get(sc.getGoodsId()).getStockVolume())) return 0;
        if (shopingOrderResData != null) {
            Double presentPayableTotal = shopingCartList.parallelStream().map(ShopingCart::getPresentPayable)
                    .reduce(0.00, (pt1, pt2) -> Arith.add(2, pt1, pt2));
            shopingOrderResData.setScAmount(presentPayableTotal);
        } else {
            updateBatchById(shopingCartList.parallelStream().map(shopingCart -> shopingCart.setStatus(1)).collect(Collectors.toList()));
            Map<String, Integer> scMap = shopingCartList.parallelStream().collect(Collectors.toMap(ShopingCart::getGoodsId, ShopingCart::getPurchaseQuantity));
            goodsService.updateBatchById(goodsList.parallelStream().map(goods -> goods.setStockVolume(goods.getStockVolume() - scMap.get(goods.getUuId()))
                    .setSalesVolume(goods.getSalesVolume() + scMap.get(goods.getUuId()))).collect(Collectors.toList()));
        }
        return shopingCartList.parallelStream().map(ShopingCart::getWeightTotal).reduce(0, Integer::sum);
    }

}
